﻿#region Copyright (c) 2013-08, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Amarok.Presentation.Resources;


namespace Amarok.Presentation.Native
{
	/// <summary>
	/// This class contains platform invokes to window-related functions.
	/// </summary>
	public static class NativeWindow
	{
		/// <summary>
		/// Retrieves information about the specified window. The function also retrieves the 32-bit (DWORD) 
		/// value at the specified offset into the extra window memory. 
		/// </summary>
		/// 
		/// <param name="hwnd">
		/// A handle to the window and, indirectly, the class to which the window belongs.</param>
		/// <param name="index">
		/// The zero-based offset to the value to be retrieved. Valid values are in the range zero through the 
		/// number of bytes of extra window memory, minus four; for example, if you specified 12 or more bytes of 
		/// extra memory, a value of 8 would be an index to the third 32-bit integer.</param>
		/// 
		/// <returns>
		/// If the function succeeds, the return value is the requested value. If the function fails, the return 
		/// value is zero. To get extended error information, call GetLastError. If SetWindowLong has not been 
		/// called previously, GetWindowLong returns zero for values in the extra window or class memory.
		/// </returns>
		public static IntPtr GetWindowLongPtr(HandleRef hwnd, Int32 index)
		{
			IntPtr result = IntPtr.Zero;
			Int32 lastError = 0;

			if (IntPtr.Size == 4)
			{
				Int32 temp = UnsafeNativeWindow.GetWindowLong(hwnd, index);
				lastError = Marshal.GetLastWin32Error();
				result = new IntPtr(temp);
			}
			else if (IntPtr.Size == 8)
			{
				result = UnsafeNativeWindow.GetWindowLongPtr(hwnd, index);
				lastError = Marshal.GetLastWin32Error();
			}
			else
			{
				throw new NotSupportedException(ExceptionResources.PlatformNotSupported);
			}

			if (result == IntPtr.Zero && lastError != 0)
				throw new Win32Exception(lastError);

			return result;
		}


		/// <summary>
		/// Changes an attribute of the specified window. The function also sets a value at the specified offset in 
		/// the extra window memory. 
		/// </summary>
		/// 
		/// <param name="hwnd">
		/// A handle to the window and, indirectly, the class to which the window belongs.</param>
		/// <param name="index">
		/// The zero-based offset to the value to be set. Valid values are in the range zero through the number 
		/// of bytes of extra window memory, minus the size of an integer. To set any other value, specify one of 
		/// the following values.</param>
		/// <param name="value">
		/// The replacement value.</param>
		/// 
		/// <returns>
		/// If the function succeeds, the return value is the previous value of the specified 32-bit integer. If 
		/// the function fails, the return value is zero. To get extended error information, call GetLastError. If 
		/// the previous value of the specified 32-bit integer is zero, and the function succeeds, the return value 
		/// is zero, but the function does not clear the last error information. This makes it difficult to determine 
		/// success or failure. To deal with this, you should clear the last error information by calling SetLastError 
		/// with 0 before calling SetWindowLong. Then, function failure will be indicated by a return value of zero 
		/// and a GetLastError result that is nonzero.
		/// </returns>
		public static void SetWindowLongPtr(HandleRef hwnd, Int32 index, IntPtr value)
		{
			IntPtr result = IntPtr.Zero;
			Int32 lastError = 0;

			if (IntPtr.Size == 4)
			{
				Int32 temp = UnsafeNativeWindow.SetWindowLong(hwnd, index, value.ToInt32());
				lastError = Marshal.GetLastWin32Error();
				result = new IntPtr(temp);
			}
			else if (IntPtr.Size == 8)
			{
				result = UnsafeNativeWindow.SetWindowLongPtr(hwnd, index, value);
				lastError = Marshal.GetLastWin32Error();
			}
			else
			{
				throw new NotSupportedException(ExceptionResources.PlatformNotSupported);
			}


			if (result == IntPtr.Zero && lastError != 0)
				throw new Win32Exception(lastError);
		}

	}
}
